#pragma once
#include <Windows.h>

#include <atomic>
#include <cassert>
#include <string>

namespace multiprocess {
namespace sync {
// https://docs.microsoft.com/zh-cn/windows/win32/sync/using-named-objects
class mutex {
  HANDLE m_handle_of_mutex;

 public:
  mutex(size_t mutex_key) { create(mutex_key); };
  ~mutex() {
    if (m_handle_of_mutex) CloseHandle(m_handle_of_mutex);
  }

  void lock() {
    assert(m_handle_of_mutex);
    while (WaitForSingleObject(m_handle_of_mutex, INFINITE) != WAIT_OBJECT_0) {
    };
  }
  void unlock() {
    assert(m_handle_of_mutex);
    ReleaseMutex(m_handle_of_mutex);
  }
  bool create(size_t mutex_key) {
    if (m_handle_of_mutex) CloseHandle(m_handle_of_mutex);
    m_handle_of_mutex =
        CreateMutex(NULL, FALSE, ::std::to_wstring(mutex_key).data());
    assert(m_handle_of_mutex != NULL);
    return GetLastError() != ERROR_ALREADY_EXISTS;
  }
  bool open(size_t mutex_key) {
    if (m_handle_of_mutex) CloseHandle(m_handle_of_mutex);
    m_handle_of_mutex =
        OpenMutex(MUTEX_ALL_ACCESS, FALSE, ::std::to_wstring(mutex_key).data());
    return m_handle_of_mutex != NULL;
  }
};
}  // namespace sync
}  // namespace multiprocess